//
//  Utility.cpp
//  germ
//
//  Created by Rodger Voelker
// 
//

#include "Utility.h"

//---------------constructors / destructor ---------------------
// Copy the command line arguments to a local list.  Start at
// argv[1] since we don't want the program name (argv[0]).
//Utility::Utility(){}

//Utility::Utility(int argc, char* argv[]){
//	initialize(argc, argv);
//}

//Utility::~Utility(){}


//--------------- getArguments() ---------------------
//read the parameters passed in argv
//need to add ability to handle duplicate switches
bool Utility::getArguments(int argc, char* argv[]) {
	if( !(argc % 2)){
		cerr << endl << "ERROR in CommmandLine::Utility: Switch/value mismatch. " << endl;
		cerr << "Possibly missing a switch or value or format incorrect" << endl;
		cerr << "Each switch must be separated from value by whitespace" << endl;
		return false;
	}
  
	//copy the command line into a vector to facilitate processing
	for (int i = 1; i < argc; i++){
		_argv.push_back(string(argv[i]));
	}
  
	//assume the contents are in switch value pairs each begining with a switch
	for( vector<string>::const_iterator current_pos = _argv.begin(); current_pos != _argv.end(); current_pos += 2){
		_commands[*current_pos] = *(current_pos + 1);
	}
	return true;
}

//--------------- copyArgv() ---------------------
vector<string> Utility::copyArgv(){
	return _argv;
}

//--------------- copyMap() ---------------------
map<string,string> Utility::copyMap(){
	return _commands;
}

//--------------- argvSize() ---------------------
int Utility::argvSize(){
	return _argv.size();
}

//--------------- print() ---------------------
void Utility::print(){
	int counter = 0;
	for(map<string,string>::const_iterator it = _commands.begin(); it != _commands.end(); ++it){
		cout << ++counter << ": " << it->first << "\t" << it->second << endl;
	}
}

//--------------- mapSwitch Overloaded---------------------
//map the value represented by the switch to the variable
bool Utility::mapSwitch(const char* theSwitch, int& variable){
	map<string,string>::const_iterator value_iter = _commands.find(theSwitch);
	if(value_iter == _commands.end()){
		return false;
	}else{
		std::stringstream ss;
		ss << value_iter->second;
		ss >> variable;
		return true;
	}
}

bool Utility::mapSwitch(const char* theSwitch, unsigned& variable){
	map<string,string>::const_iterator value_iter = _commands.find(theSwitch);
	if(value_iter == _commands.end()){
		return false;
	}else{
		std::stringstream ss;
		ss << value_iter->second;
		ss >> variable;
		return true;
	}
}

bool Utility::mapSwitch(const char* theSwitch, long& variable){
	map<string,string>::const_iterator value_iter = _commands.find(theSwitch);
	if(value_iter == _commands.end()){
		return false;
	}else{
		std::stringstream ss;
		ss << value_iter->second;
		ss >> variable;
		return true;
	}
}

bool Utility::mapSwitch(const char* theSwitch, float& variable){
	map<string,string>::const_iterator value_iter = _commands.find(theSwitch);
	if(value_iter == _commands.end()){
		return false;
	}else{
		std::stringstream ss;
		ss << value_iter->second;
		ss >> variable;
		return true;
	}
}

bool Utility::mapSwitch(const char* theSwitch, double& variable){
	map<string,string>::const_iterator value_iter = _commands.find(theSwitch);
	if(value_iter == _commands.end()){
		return false;
	}else{
		std::stringstream ss;
		ss << value_iter->second;
		ss >> variable;
		return true;
	}
}

bool Utility::mapSwitch(const char* theSwitch, const char*  &variable){
	map<string,string>::const_iterator value_iter = _commands.find(theSwitch);
	if(value_iter == _commands.end()){
		return false;
	}else{
		variable = (value_iter->second.c_str());
		return true;
	}
}

bool Utility::mapSwitch(const char* theSwitch, string& variable){
	map<string,string>::const_iterator value_iter = _commands.find(theSwitch);
	if(value_iter == _commands.end()){
		return false;
	}else{
		variable = value_iter->second;
		return true;
	}
}

bool Utility::mapSwitch(const char* theSwitch, bool& variable){
	map<string,string>::const_iterator value_iter = _commands.find(theSwitch);
	if(value_iter == _commands.end()){
		return false;
	}else{
		string input = value_iter->second.c_str();
		if( input == "Y" || input == "y" || input == "t" || input == "T" || input == "1" ||
       input == "yes" || input == "Yes" || input == "True" || input == "true" ||
       input == "yo" || input == "yah" || input == "si" || input == "oui" || input == "of_course" ||
       input == "nein" || input == "nope" || input == "no_way_dude" || input == "not_a_chance" ||
       input == "N" || input == "n" || input == "f" || input == "F" || input == "0" ||
       input == "no" || input == "No" || input == "False" || input == "false" ){
			if( input == "Y" || input == "y" || input == "t" || input == "T" || input == "1" ||
         input == "yo" || input == "yah" || input == "si" || input == "oui" || input == "of_course" ||
         input == "yes" || input == "Yes" || input == "True" || input == "true" ){
				variable = true;
      }else{
			 	variable = false;
      }
		}else{
			cerr << "Switch is not of type bool. Will use false as default." << endl;
			variable = false;
			return false;
		}
		return true;
	}
}

// ---------------------- getUnsigned() --------------------------------------
unsigned Utility::getUnsigned( string query_message ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	return stringToUnsigned( input_buffer );
}

// ---------------------- getUnsignedWithDefault() --------------------------------------
//assign default string if nothing entered
unsigned Utility::getUnsignedWithDefault( string query_message, unsigned default_value ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	if( input_buffer == "" ){
		return default_value;
	}else{
		return stringToUnsigned( input_buffer );
	}
}

// ---------------------- getUnsignedWithBounds() --------------------------------------
unsigned Utility::getUnsignedWithBounds( string query_message, unsigned lowrange, unsigned highrange ){
	string input_buffer;
	unsigned result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		result = stringToUnsigned( input_buffer );
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- getUnsignedWithDefaultWithBounds() --------------------------------------
unsigned Utility::getUnsignedWithDefaultWithBounds( string query_message, unsigned default_value, unsigned lowrange, unsigned highrange ){
	if( default_value < lowrange || default_value > highrange ){
		cerr << "IN: unsigned Utility::getUnsigned( string query_message, unsigned default_value, unsigned lowrange, unsigned highrange ): " << endl;
		cerr << "ERROR: default value is out of bounds. " << endl;
		exit(1);
	}
	string input_buffer;
	unsigned result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		if( input_buffer == "" ){
			return default_value;
		}else{
			result = stringToUnsigned( input_buffer );
		}
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- stringToUnsigned() --------------------------------------
unsigned Utility::stringToUnsigned( string& source ){
	std::stringstream strstr;
	strstr << source;
	unsigned result;
	strstr >> result;
	return result;
}

// ---------------------- getInt() --------------------------------------
int Utility::getInt( string query_message ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	return stringToInt( input_buffer );
}

// ---------------------- getIntWithDefault() --------------------------------------
//assign default string if nothing entered
int Utility::getIntWithDefault( string query_message, int default_value ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	if( input_buffer == "" ){
		return default_value;
	}else{
		return stringToInt( input_buffer );
	}
}

// ---------------------- getIntWithBounds() --------------------------------------
int Utility::getIntWithBounds( string query_message, int lowrange, int highrange ){
	string input_buffer;
	int result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		result = stringToInt( input_buffer );
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- getIntWithDefaultWithBounds() --------------------------------------
int Utility::getIntWithDefaultWithBounds( string query_message, int default_value, int lowrange, int highrange ){
	if( default_value < lowrange || default_value > highrange ){
		cerr << "IN: int Utility::getInt( string query_message, int default_value, int lowrange, int highrange ): " << endl;
		cerr << "ERROR: default value is out of bounds. " << endl;
		exit(1);
	}
	string input_buffer;
	int result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		if( input_buffer == "" ){
			return default_value;
		}else{
			result = stringToInt( input_buffer );
		}
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- stringToInt() --------------------------------------
int Utility::stringToInt( string& source ){
	std::stringstream strstr;
	strstr << source;
	int result;
	strstr >> result;
	return result;
}

// ---------------------- getLong() --------------------------------------
long Utility::getLong( string query_message ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	return stringToLong( input_buffer );
}

// ---------------------- getLongWithDefault() --------------------------------------
//assign default string if nothing entered
long Utility::getLongWithDefault( string query_message, long default_value ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	if( input_buffer == "" ){
		return default_value;
	}else{
		return stringToLong( input_buffer );
	}
}

// ---------------------- getLongWithBounds() --------------------------------------
long Utility::getLongWithBounds( string query_message, long lowrange, long highrange ){
	string input_buffer;
	long result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		result = stringToLong( input_buffer );
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- getLongWithDefaultWithBounds() --------------------------------------
long Utility::getLongWithDefaultWithBounds( string query_message, long default_value, long lowrange, long highrange ){
	if( default_value < lowrange || default_value > highrange ){
		cerr << "IN: long Utility::getLong( string query_message, long default_value, long lowrange, long highrange ): " << endl;
		cerr << "ERROR: default value is out of bounds. " << endl;
		exit(1);
	}
	string input_buffer;
	long result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		if( input_buffer == "" ){
			return default_value;
		}else{
			result = stringToLong( input_buffer );
		}
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- stringToLong() --------------------------------------
long Utility::stringToLong( string& source ){
	std::stringstream strstr;
	strstr << source;
	long result;
	strstr >> result;
	return result;
}

// ---------------------- stringToUnsignedLong() --------------------------------------
unsigned long Utility::stringToUnsignedLong( string& source ){
	std::stringstream strstr;
	strstr << source;
	unsigned long result;
	strstr >> result;
	return result;
}

// ---------------------- getFloat() --------------------------------------
float Utility::getFloat( string query_message ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	return stringToFloat( input_buffer );
}

// ---------------------- getFloatWithDefault() --------------------------------------
//assign default string if nothing entered
float Utility::getFloatWithDefault( string query_message, float default_value ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	if( input_buffer == "" ){
		return default_value;
	}else{
		return stringToFloat( input_buffer );
	}
}

// ---------------------- getFloatWithBounds() --------------------------------------
float Utility::getFloatWithBounds( string query_message, float lowrange, float highrange ){
	string input_buffer;
	float result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		result = stringToFloat( input_buffer );
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- getFloatWithDefaultWithBounds() --------------------------------------
float Utility::getFloatWithDefaultWithBounds( string query_message, float default_value, float lowrange, float highrange ){
	if( default_value < lowrange || default_value > highrange ){
		cerr << "IN: float Utility::getFloat( string query_message, float default_value, float lowrange, float highrange ): " << endl;
		cerr << "ERROR: default value is out of bounds. " << endl;
		exit(1);
	}
	string input_buffer;
	float result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		if( input_buffer == "" ){
			return default_value;
		}else{
			result = stringToFloat( input_buffer );
		}
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- stringToFloat() --------------------------------------
float Utility::stringToFloat( string& source ){
	std::stringstream strstr;
	strstr << source;
	float result;
	strstr >> result;
	return result;
}

// ---------------------- getDouble() --------------------------------------
double Utility::getDouble( string query_message ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	return stringToDouble( input_buffer );
}

// ---------------------- getDoubleWithDefault() --------------------------------------
//assign default string if nothing entered
double Utility::getDoubleWithDefault( string query_message, double default_value ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	if( input_buffer == "" ){
		return default_value;
	}else{
		return stringToDouble( input_buffer );
	}
}

// ---------------------- getDoubleWithBounds() --------------------------------------
double Utility::getDoubleWithBounds( string query_message, double lowrange, double highrange ){
	string input_buffer;
	double result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		result = stringToDouble( input_buffer );
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- getDoubleWithDefaultWithBounds() --------------------------------------
double Utility::getDoubleWithDefaultWithBounds( string query_message, double default_value, double lowrange, double highrange ){
	if( default_value < lowrange || default_value > highrange ){
		cerr << "IN: double Utility::getDouble( string query_message, double default_value, double lowrange, double highrange ): " << endl;
		cerr << "ERROR: default value is out of bounds. " << endl;
		exit(1);
	}
	string input_buffer;
	double result;
	bool isOK = false;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input_buffer, '\n');
		if( input_buffer == "" ){
			return default_value;
		}else{
			result = stringToDouble( input_buffer );
		}
		if( result < lowrange || result > highrange ){
			cout << "The acceptable range is from " << lowrange << " to " << highrange << "." << endl;
		}else{
			isOK = true;
		}
	}
	return result;
}

// ---------------------- stringToDouble() --------------------------------------
double Utility::stringToDouble( string& source ){
	std::stringstream strstr;
	strstr << source;
	double result;
	strstr >> result;
	return result;
}

// ---------------------- getString() --------------------------------------
//assign default string if nothing entered
string Utility::getString( string query_message ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	return input_buffer;
}

// ---------------------- getStringWithDefault() --------------------------------------
//assign default string if nothing entered
string Utility::getStringWithDefault( string query_message, string defaultstring ){
	string input_buffer;
	cout << query_message;
	std::getline(cin, input_buffer, '\n');
	if( input_buffer == "" ){
		return defaultstring;
	}else{
		return input_buffer;
	}
}

// ---------------------- getBool --------------------------------------
bool Utility::getBool( string query_message ){
	string input = "";
	bool isOK = false;
	bool answer = true;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input, '\n');
		if( input == "Y" || input == "y" || input == "t" || input == "T" || input == "1" ||
       input == "yes" || input == "Yes" || input == "True" || input == "true" ||
       input == "yo" || input == "yah" || input == "si" || input == "oui" || input == "of_course" ||
       input == "nein" || input == "nope" || input == "no_way_dude" || input == "not_a_chance" ||
       input == "N" || input == "n" || input == "f" || input == "F" || input == "0" ||
       input == "no" || input == "No" || input == "False" || input == "false" ){
			if( input == "Y" || input == "y" || input == "t" || input == "T" || input == "1" ||
         input == "yo" || input == "yah" || input == "si" || input == "oui" || input == "of_course" ||
         input == "yes" || input == "Yes" || input == "True" || input == "true" ){
        answer = true;
        isOK = true;
			}else{
				isOK = true;
				answer = false;
			}
		}else{
			cerr << "Acceptable input values are: y/Y/t/T/yes/Yes/true/True/1 or n/N/f/F/no/No/false/False/0. " << endl;
			cerr << "Please enter an appropriate response. " << endl;
		}
	}
	return answer;
}

// ---------------------- getBoolWithDefault --------------------------------------
bool Utility::getBoolWithDefault( string query_message, bool default_state ){
	string input = "";
	bool isOK = false;
	bool answer = default_state;
	while( !isOK ){
		cout << query_message;
		std::getline(cin, input, '\n');
		if( input == "" ){
			return answer;
		}
		if( input == "Y" || input == "y" || input == "t" || input == "T" || input == "1" ||
       input == "yes" || input == "Yes" || input == "True" || input == "true" ||
       input == "yo" || input == "yah" || input == "si" || input == "oui" || input == "of_course" ||
       input == "nein" || input == "nope" || input == "no_way_dude" || input == "not_a_chance" ||
       input == "N" || input == "n" || input == "f" || input == "F" || input == "0" ||
       input == "no" || input == "No" || input == "False" || input == "false" ){
			if( input == "Y" || input == "y" || input == "t" || input == "T" || input == "1" ||
         input == "yo" || input == "yah" || input == "si" || input == "oui" || input == "of_course" ||
         input == "yes" || input == "Yes" || input == "True" || input == "true" ){
        answer = true;
        isOK = true;
			}else{
				isOK = true;
				answer = false;
			}
		}else{
			cerr << "Acceptable input values are: y/Y/t/T/yes/Yes/true/True/1 or n/N/f/F/no/No/false/False/0. " << endl;
			cerr << "Please enter an appropriate response. " << endl;
		}
	}
	return answer;
}

//-------------- getFileNamePrefix ---------------------
string Utility::getFileNamePrefix( string& instring ){
	vector<string> splitname = _splitPeriod( instring );
	if( splitname.size() < 2 ){
		cerr << "Warning: While extracting filename parts: " << endl;
		cerr << "Expected a single period but found none. Filename \"" << instring << "\" is not properly formatted." << endl;
		cerr << "Returning input string." << endl;
		return instring;
	}else if( splitname.size() > 2 ){
		cerr << "Warning: While extracting filename parts: " << endl;
		cerr << "Expected a single period but found multiple. Filename \"" << instring << "\" is not properly formatted." << endl;
		cerr << "Returning input string." << endl;
		return instring;
	}
	return splitname[0];
}

//-------------- getFileNameSuffix ---------------------
string Utility::getFileNameSuffix( string& instring ){
	vector<string> splitname = _splitPeriod( instring );
	if( splitname.size() < 2 ){
		cerr << "Warning: While extracting filename parts: " << endl;
		cerr << "Expected a single period but found none. Filename \"" << instring << "\" is not properly formatted." << endl;
		cerr << "Returning input string." << endl;
		return instring;
	}else if( splitname.size() > 2 ){
		cerr << "Warning: While extracting filename parts: " << endl;
		cerr << "Expected a single period but found multiple. Filename \"" << instring << "\" is not properly formatted." << endl;
		cerr << "Returning input string." << endl;
		return instring;
	}
	return splitname[1];
}

//-------------  _splitPeriod() ------------------------
//split string on periods and put into vector
vector<string> Utility::_splitPeriod(string& instring ){
	vector<string> outvec;
	string::const_iterator begin_copy = instring.begin();
	string::const_iterator end_copy;
	string::const_iterator end_line = instring.end();
	while(begin_copy != end_line){
		begin_copy = std::find_if(begin_copy, end_line, Utility::NotPeriod() );
		end_copy = std::find(begin_copy, end_line, '.' );
		if( begin_copy != end_line ){
			outvec.push_back( string(begin_copy, end_copy) );
		}
		begin_copy = end_copy;
	}
	return outvec;
}

// ------------------------- substr() ---------------------------
// The heart of any function taking a substring, it allows substrings starting from the begining or the end and returns true or false if
// a substring can be made using the parameters passed. User Tests success by looking at length of string returned
// if error (or if <use_strict> = true && length < sublen) then returns empty string
// Parameters:
//				<sublen> = length of substring to return, if 0 then return full string minus offset
//				<offset> = length from front or end of string that will be removed
//				<anchor> = 1 or -1, 1= offset from start, -1 = offset from end
//				<use_strict> = return string only if substring length = <length>
string Utility::substr( const string& instring, int offset, int sublen, int anchor, bool use_strict ){
	string nullstring = "";
	if( anchor != 1 && anchor != -1 ){ cerr << "\n!ERROR in Utility::substr(). Anchor must = 1 or -1. Null string returned." << endl; return nullstring; }
	if( offset < 0 ){ cerr << "\n!ERROR in Utility::substr(). Invalid offset parameter. Offset must be >= 0. " << endl; return nullstring; }
	if( sublen < 0 ){ cerr << "\n!ERROR in Utility::substr(). Invalid sublen parameter. Length must be >= 0. " << endl; return nullstring; }
	int strlen = instring.size();
	if( offset == 0 && sublen == 0 ) return instring;
	if( anchor == 1 ){
		if( strlen >= offset +1 ){
			if( sublen == 0 ){ //take until end of line
				return instring.substr( offset, strlen - offset);
			}
			if( strlen >= sublen + offset ){ //get full subseq length = sublen
				return instring.substr( offset, sublen );
			}else{ //instring is too short for full subseq = sublen
				if( use_strict ){
					return nullstring; //return it unchanged
				}else{ //get from start to end of instring
					return instring.substr( offset, strlen - offset);
				}
			}
		}else{ //nothing left to return
			return nullstring;
		}
	}else{
		if( strlen >= offset +1 ){
			if( sublen == 0 ){ //return start - offset
				return instring.substr( 0, strlen - offset);
			}
			if( strlen >= sublen + offset ){ //get full subseq length = sublen
				return instring.substr( strlen - offset - sublen, sublen );
			}else{ //instring is too short for full subseq = sublen
				if( use_strict ){
					return nullstring; //return it unchanged
				}else{ //return start - offset
					return instring.substr( 0, strlen - offset);
				}
			}
		}else{ //nothing left to return
			return nullstring;
		}
	}
}

//--------------- verifyFileExists -------------------------
bool Utility::verifyFileExists(string& file){
	if( !file.size() ) return false;
	ifstream testFH( file.c_str() );
	bool status = false;
	if( testFH ){
		status = true;
	}
	testFH.close();
	return status;
}

//-------------  splitSpace() ------------------------
//split line on spaces and put results into vector
unsigned Utility::splitSpace(string& instring, vector<string>& outvec){
	outvec.clear();
	string::const_iterator begin_copy = instring.begin();
	string::const_iterator end_copy;
	string::const_iterator end_line = instring.end();
	while(begin_copy != end_line){
		begin_copy = std::find_if(begin_copy, end_line, NotSpace() );
		end_copy = std::find(begin_copy, end_line, ' ' );
		if( begin_copy != end_line ){
			outvec.push_back( std::string(begin_copy, end_copy) );
		}
		begin_copy = end_copy;
	}
	return outvec.size();
}

//split line on spaces and put results into vector
unsigned Utility::splitSpace(string& instring, vector<int>& outvec){
	outvec.clear();
	string::const_iterator begin_copy = instring.begin();
	string::const_iterator end_copy;
	string::const_iterator end_line = instring.end();
	while(begin_copy != end_line){
		begin_copy = std::find_if(begin_copy, end_line, NotSpace() );
		end_copy = std::find(begin_copy, end_line, ' ' );
		if( begin_copy != end_line ){
			string input = string(begin_copy, end_copy);
			outvec.push_back( stringToInt(input) );
		}
		begin_copy = end_copy;
	}
	return outvec.size();
}

//-------------  splitComma() ------------------------
//split line on commas and put results into vector
unsigned Utility::splitComma(string& instring, vector<string>& outvec){
	outvec.clear();
	string::const_iterator begin_copy = instring.begin();
	string::const_iterator end_copy;
	string::const_iterator end_line = instring.end();
	while(begin_copy != end_line){
		begin_copy = std::find_if(begin_copy, end_line, NotComma() );
		end_copy = std::find(begin_copy, end_line, ',' );
		if( begin_copy != end_line ){
			outvec.push_back( std::string(begin_copy, end_copy) );
		}
		begin_copy = end_copy;
	}
	return outvec.size();
}

//-------------  splitTab() ------------------------
//split line on tabs and put results into vector
unsigned Utility::splitTab(string& instring, vector<string>& outvec){
	outvec.clear();
	string::const_iterator begin_copy = instring.begin();
	string::const_iterator end_copy;
	string::const_iterator end_line = instring.end();
	while(begin_copy != end_line){
		begin_copy = std::find_if(begin_copy, end_line, NotTab() );
		end_copy = std::find(begin_copy, end_line, '\t' );
		if( begin_copy != end_line ){
			outvec.push_back( std::string(begin_copy, end_copy) );
		}
		begin_copy = end_copy;
	}
	return outvec.size();
}

//-------------  split() ------------------------
//split line on delimiter and put results into vector
unsigned Utility::split(string& instring, vector<string>& outvec, char delimiter){
	outvec.clear();
	string::const_iterator begin_copy = instring.begin();
	string::const_iterator end_copy;
	string::const_iterator end_line = instring.end();
	while(begin_copy != end_line){
		begin_copy = std::find_if(begin_copy, end_line, bind2nd(not_equal_to<char>(), delimiter) );
		end_copy = std::find(begin_copy, end_line, delimiter );
		if( begin_copy != end_line ){
			outvec.push_back( std::string(begin_copy, end_copy) );
		}
		begin_copy = end_copy;
	}
	return outvec.size();
}

//-------------  splitLower() ------------------------
//split line on lower case and put results into vector
unsigned Utility::splitLower(string& instring, vector<string>& outvec){
	outvec.clear();
	string::const_iterator begin_copy = instring.begin();
	string::const_iterator end_copy;
	string::const_iterator end_line = instring.end();
	while(begin_copy != end_line){
		begin_copy = std::find_if(begin_copy, end_line, NotLower() );
		end_copy = std::find_if(begin_copy, end_line, NotUpper() );
		if( begin_copy != end_line ){
			outvec.push_back( std::string(begin_copy, end_copy) );
		}
		begin_copy = end_copy;
	}
	return outvec.size();
}

//----------------- seqToBase10 -----------------------------------------
//convert a sequence into a base4 number where A=0, C=1, G=2, T=3 and return the base10 representation
bool Utility::seqToBase10( const string& seq, int& nb10 ){
	//convert the seq into the base4 representation
	unsigned seqlen = seq.size();
	if( seqlen > 15 ){
		cerr << "ERROR: conversion is limited to seq strings <= 15 bases" << endl;
		nb10 = 0;
		return false;
	}
	long nb4A[ seqlen+1 ];
	for(unsigned i=0; i< seqlen; ++i){
		switch( seq.at(i) ){
			case 'A':
				nb4A[i] = 0;
				break;
			case 'C':
				nb4A[i] = 1;
				break;
			case 'G':
				nb4A[i] = 2;
				break;
			case 'T':
				nb4A[i] = 3;
				break;
			default:
        //	cerr << "ERROR: in seq conversion, seq contains unacceptable characters. " << endl;
				nb10 = 0;
				return false;
		}
	}
	//convert to base 10
	nb10 = 0;
	for(unsigned i=0; i< seqlen; ++i){
		nb10 = (nb10*4L) + nb4A[i];
	}
	return true;
}

//----------------- base10ToSeq -----------------------------------------
//convert a base 10 number into the sequence representation based upon base4 system where A=0, C=1, G=2, T=3
//len is the length of the expected seq, used to pad left for left A's
bool Utility::base10ToSeq( int n, string& seq, int patlen ){
	if( n>1073741823){
		cerr << "ERROR: conversion is currently limited to 1073741823 (which is the max base10 equiv of 15 bases )" << endl;
		seq = "";
		return false;
	}
	int nb4[20];
	unsigned seqlen=0;
	if( n==0 ){
		string pad( patlen, 'A');
		seq = pad;
		return true;
	}
	while( n > 0 ){
		nb4[seqlen] = n % 4;
		n = n/4;
		++seqlen;
	}
	seq.resize(seqlen);
	for(unsigned i=0; i< seqlen; ++i){
		switch( nb4[i] ){
			case 0:
				seq[seqlen-i-1] = 'A';
				break;
			case 1:
				seq[seqlen-i-1] = 'C';
				break;
			case 2:
				seq[seqlen-i-1] = 'G';
				break;
			case 3:
				seq[seqlen-i-1] = 'T';
				break;
			default:
        //	cerr << "ERROR: in seq conversion, seq contains unacceptable characters. " << endl;
				seq = "";
				return false;
		}
	}
	//add padding if needed
	if( (int)seqlen < patlen ){
		string pad( (patlen-seqlen), 'A');
		seq = pad + seq;
	}
	return true;
}

//----------- toUpper ------------------
void Utility::toUpper( string& instring ){
	for(string::iterator it = instring.begin(); it != instring.end(); ++it){
		if( !std::isupper(*it) ){
			*it = std::toupper(*it);
		}
	}
}

